﻿#include "../../beans/headers/BlockItemClass.h"

BlockItemClass::BlockItemClass(int blockTypeID,int blockID,QObject *parent):m_BlockType(blockTypeID),m_BlockID(blockID)
{
    Q_UNUSED(parent)
    this->initial();
}

//
BlockItemClass::~BlockItemClass(void)
{

}

// 辅助方法（初始化模块元素）
void BlockItemClass::initial(void)
{
    m_BlockItem = this->createBlockItem();
    m_TextItem = this->createTextItem();
    m_DotItem_List = this->createDotItems();
    m_SquareItem_List = this->createSquareItems();

    this->updateTextItem();
    this->updateDotItem();
    this->updateSquareItem();
}

// 释放BlockItem
void BlockItemClass::deleteBlockItem(void)
{
    delete m_BlockItem;
    m_BlockItem = Q_NULLPTR;
    m_TextItem = Q_NULLPTR;

    m_DotItem_List.clear();
    m_SquareItem_List.clear();

}

// 槽函数（BlockItem是否被选中,初始blockItem被选中和没被选中的状态）
void BlockItemClass::slot_BlockItemIsSelected(bool isSelected)
{
    // 模块被选中时显示，没被选中时不显示
    this->setSquareItemVisible(isSelected);

    //
    this->setDotItemVisible(isSelected);
}

// 槽函数（鼠标在BlockItem上时显示圆点，不在就不显示）
void BlockItemClass::slot_BlockItemContainsCursorPos(bool isContains)
{

    this->setDotItemVisible(isContains);

}

// 辅助方法（显示场景模块）
void BlockItemClass::showItem(ItemScene *scene)
{
    scene->addItem(m_BlockItem);
    m_BlockItem->show();
    m_TextItem->show();

    foreach (DotItem *dotItem, m_DotItem_List)
    {
        dotItem->show();
    }

    foreach (SquareItem *squareItem, m_SquareItem_List)
    {
        squareItem->show();
    }
}

// 更新显示：报错本身和子部件已经内容显示
void BlockItemClass::updateBlockItem(void)
{


    this->updateDotItem();
    this->updateSquareItem();
    this->updateTextItem();
}

// 辅助方法（缩放模块单元）
void BlockItemClass::zoomBlockItem(SquareItem *squareItem, QPointF cursorPos)
{
    // 枚举变量：squareItem在BlockItem四个角的方位标识
    int squareItemDirection;

    // BlockItem的初始坐标
    QPointF oldBlockPos;

    // 缩放后模块新坐标点（因为除了通过左下角缩放，都会改变坐标，因为坐标是以左上角为基准的）
    QPointF newBlockPos;

    // 缩放时静止不动的点（举例：如果通过左下角缩放，那么右上角就是静止不动的点）
    QPointF staticPos;

    // 鼠标点cursorPos所在的角的顶点坐标(指的是BlockItem的角的坐标,注意不是cursorPos因为有一点偏移量）
    // 此版本还没开发这个偏移功能，有了这个功能在缩放时鼠标的样式就不会改变了（还有一个方案，可以尝试，就是将SquareItem设置为可选择可移动，以此来缩放）
    QPointF movePos;

    // 理论上缩放后最小的点坐标
    QPointF minPos;

    qreal blockWidth,blockHeight;

    // 限制最小缩放大小坐标数值
    qreal x,y;

    squareItemDirection = squareItem->data(ITEM_TYPE).toInt();
    oldBlockPos = m_BlockItem->scenePos();
    blockWidth = m_BlockItem->boundingRect().width();
    blockHeight = m_BlockItem->boundingRect().height();

    // 确定静止点
    switch (squareItemDirection)
    {
        case EnumType::SquareItem_LeftTop:

            // 缩放时静止不动的点：即BlockItem右下角点坐标
            staticPos = oldBlockPos + QPointF(blockWidth,blockHeight);
            minPos = staticPos + QPointF( -100.0, -50.0);

            // 限制缩放最小大小
            x = (cursorPos.rx() >= minPos.rx() ? minPos.rx() : cursorPos.rx());
            y = (cursorPos.ry() >= minPos.ry() ? minPos.ry() : cursorPos.ry());
            movePos = QPointF(x,y) + QPointF( -SquareItem::SQUAREITEM_WIDTH / 2, -SquareItem::SQUAREITEM_WIDTH / 2);

            newBlockPos = movePos;
            blockWidth = staticPos.rx() - movePos.rx();
            blockHeight = staticPos.ry() - movePos.ry();

            break;
        case EnumType::SquareItem_LeftBottom:

            // 缩放时静止不动的点：即BlockItem右上角点坐标
            staticPos = oldBlockPos + QPointF(blockWidth,0.0);
            minPos = staticPos + QPointF(-100.0, +50);

            // 限制缩放最小大小
            x = (cursorPos.rx() >= minPos.rx() ? minPos.rx() : cursorPos.rx());
            y = (cursorPos.ry() <= minPos.ry() ? minPos.ry() : cursorPos.ry());
            movePos = QPointF(x,y) + QPointF( -SquareItem::SQUAREITEM_WIDTH / 2, +SquareItem::SQUAREITEM_WIDTH / 2);

            newBlockPos = QPointF(movePos.rx(),staticPos.ry());
            blockWidth = staticPos.rx() - movePos.rx();
            blockHeight = movePos.ry() - staticPos.ry();

            break;
        case EnumType::SquareItem_RightBottom:

            // 缩放时静止不动的点：即BlockItem左上角点坐标
            staticPos = oldBlockPos;
            minPos = staticPos + QPointF(+100.0, +50.0);

            // 限制缩放最小大小
            x = (cursorPos.rx() <= minPos.rx() ? minPos.rx() : cursorPos.rx());
            y = (cursorPos.ry() <= minPos.ry() ? minPos.ry() : cursorPos.ry());
            movePos = QPointF(x,y) + QPointF( +SquareItem::SQUAREITEM_WIDTH / 2, +SquareItem::SQUAREITEM_WIDTH / 2);

            newBlockPos = oldBlockPos;
            blockWidth = movePos.rx() - staticPos.rx() ;
            blockHeight = movePos.ry() - staticPos.ry() ;
            break;
        case EnumType::SquareItem_RightTop:

            // 缩放时静止不动的点：即BlockItem左下角点坐标
            staticPos = oldBlockPos + QPointF(0.0,blockHeight);
            minPos = staticPos + QPointF(+100.0,-50.0);

            // 限制缩放最小大小
            x = (cursorPos.rx() <= minPos.rx() ? minPos.rx() : cursorPos.rx());
            y = (cursorPos.ry() >= minPos.ry() ? minPos.ry() : cursorPos.ry());
            movePos = QPointF(x,y) + QPointF( +SquareItem::SQUAREITEM_WIDTH / 2, -SquareItem::SQUAREITEM_WIDTH / 2);

            newBlockPos = QPointF(staticPos.rx(),movePos.ry());
            blockWidth = movePos.rx() - staticPos.rx();
            blockHeight = staticPos.ry() - movePos.ry();
            break;
        default:
            break;
    }

    // 限制缩放大小
    m_BlockItem->setPos(newBlockPos);
    m_BlockItem->setWidth(blockWidth);
    m_BlockItem->setHeight(blockHeight);

    updateSquareItem();
    updateDotItem();
    updateTextItem();

}

// 取值方法（模块位置,存模块的左上和右下）
QVector<qreal> BlockItemClass::getBlockPos(void)
{
    QVector<qreal> leftTopAndRightButtomPos_Vec;
    qreal leftTopPos_rx,leftTopPos_ry,RightButtomPos_rx,RightButtomPos_ry;
    leftTopPos_rx = m_BlockItem->scenePos().rx();
    leftTopPos_ry = m_BlockItem->scenePos().ry();
    RightButtomPos_rx = m_BlockItem->scenePos().rx() + m_BlockItem->boundingRect().width();
    RightButtomPos_ry = m_BlockItem->scenePos().rx() + m_BlockItem->boundingRect().height();

    leftTopAndRightButtomPos_Vec.append(leftTopPos_rx);
    leftTopAndRightButtomPos_Vec.append(leftTopPos_ry);
    leftTopAndRightButtomPos_Vec.append(RightButtomPos_rx);
    leftTopAndRightButtomPos_Vec.append(RightButtomPos_ry);

    return leftTopAndRightButtomPos_Vec;
}

// 辅助方法（创建空白模块单元）
FlowBlockItem *BlockItemClass::createBlockItem(void)
{
    FlowBlockItem *blockItem;
    blockItem = new FlowBlockItem(m_BlockType,m_BlockID);
    connect(blockItem,SIGNAL(signal_BlockItemIsSelected(bool)),this,SLOT(slot_BlockItemIsSelected(bool)));
    connect(blockItem,SIGNAL(signal_BlockItemContainsSceneCursorPos(bool)),this,SLOT(slot_BlockItemContainsCursorPos(bool)));

    return blockItem;
}

// 辅助方法（创建空白模块文本）
TextItem *BlockItemClass::createTextItem(void)
{
    TextItem *textItem;

    qreal textItemWidth,textItemHeight,offset;

    offset = 10.0;
    textItemWidth = m_BlockItem->boundingRect().width()-2*offset;
    textItemHeight = m_BlockItem->boundingRect().height() - 2*SquareItem::SQUAREITEM_WIDTH;

    textItem = new TextItem(m_BlockItem);
    textItem->setWidth(textItemWidth);
    textItem->setHeight(textItemHeight);
    textItem->setPos(offset,SquareItem::SQUAREITEM_WIDTH);


    // 设置文本为居中显示
    auto document = textItem->document();
    auto option = document->defaultTextOption();
    option.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    document->setDefaultTextOption(option);
    textItem->setTextWidth(textItemWidth);

    textItem->setPlainText( QString("ItemID:")+ QString::number(m_BlockID));


    return textItem;
}

// 辅助方法（创建模块缩放单元）
QList<SquareItem *> BlockItemClass::createSquareItems(void)
{
    QList<SquareItem *> squareItems;

    SquareItem *squareItem_LeftTop = new SquareItem(EnumType::SquareItem_LeftTop,m_BlockItem);
    SquareItem *dotItem_LeftBottom = new SquareItem(EnumType::SquareItem_LeftBottom,m_BlockItem);
    SquareItem *dotItem_RightBottom = new SquareItem(EnumType::SquareItem_RightBottom,m_BlockItem);
    SquareItem *dotItem_RightTop = new SquareItem(EnumType::SquareItem_RightTop,m_BlockItem);

    squareItems.append(squareItem_LeftTop);
    squareItems.append(dotItem_LeftBottom);
    squareItems.append(dotItem_RightBottom);
    squareItems.append(dotItem_RightTop);

    return squareItems;
}

// 辅助方法（创建端口单元）
QList<DotItem *> BlockItemClass::createDotItems(void)
{
    QList<DotItem *> dotItems;

    DotItem *dotItem_Top = new DotItem(EnumType::DotItem_Top,m_BlockItem);
    DotItem *dotItem_Left = new DotItem(EnumType::DotItem_Left,m_BlockItem);
    DotItem *dotItem_Bottom = new DotItem(EnumType::DotItem_Bottom,m_BlockItem);
    DotItem *dotItem_Right = new DotItem(EnumType::DotItem_Right,m_BlockItem);

    dotItems.append(dotItem_Top);
    dotItems.append(dotItem_Left);
    dotItems.append(dotItem_Bottom);
    dotItems.append(dotItem_Right);

    return dotItems;
}

// 辅助方法（更新模块文本）
void BlockItemClass::updateTextItem(void)
{
    qreal width,height,offset;

    offset = 10.0;
    width = m_BlockItem->boundingRect().width() -2*offset;
    height = m_BlockItem->boundingRect().height() - 2*SquareItem::SQUAREITEM_WIDTH;

    /*
    // 让m_TextItem根据动态输入的文字居中显示在父BlockItem中
    qreal x = (width - this->m_TextItem->boundingRect().width()) / 2 ;
    qreal y = (height - this->m_TextItem->boundingRect().height()) / 2 ;
    this->m_TextItem->setPos(x,y);
    */

    m_TextItem->setTextWidth(width);
    m_TextItem->setWidth(width);
    m_TextItem->setHeight(height);
}

// 辅助方法（更新缩放控件）
void BlockItemClass::updateDotItem(void)
{
    qreal width,height;

    width = m_BlockItem->boundingRect().width();
    height = m_BlockItem->boundingRect().height();

    foreach (DotItem *dotItem, m_DotItem_List)
    {
        // Dotitem在BlockItem中的坐标
        qreal x,y;

        // DotItem在BlockItem上的方位
        int direction = dotItem->data(ITEM_TYPE).toInt();

        switch (direction)
        {
            case EnumType::DotItem_Top:
                x = width / 2 - DotItem::DOTITEM_WIDTH / 2;
                y = 0.0 - DotItem::DOTITEM_WIDTH / 2;
                break;

            case EnumType::DotItem_Bottom:
                x = width / 2 - DotItem::DOTITEM_WIDTH / 2;
                y = height  - DotItem::DOTITEM_WIDTH / 2;
                break;

            case EnumType::DotItem_Left:
                x = 0.0 - DotItem::DOTITEM_WIDTH / 2;
                y = height / 2 - DotItem::DOTITEM_WIDTH / 2;
                break;

            case EnumType::DotItem_Right:
                x = width  - DotItem::DOTITEM_WIDTH / 2;
                y = height / 2 - DotItem::DOTITEM_WIDTH / 2;
                break;

            default:
                break;
        }

        dotItem->setPos(x,y);

    }

}

// 辅助方法（更新缩放控件）
void BlockItemClass::updateSquareItem(void)
{
    qreal width,height;

    width = m_BlockItem->boundingRect().width();
    height = m_BlockItem->boundingRect().height();

    foreach (SquareItem *squareItem, m_SquareItem_List)
    {
        // Dotitem在BlockItem中的坐标
        qreal x,y;

        // DotItem在BlockItem上的方位
        int direction = squareItem->data(ITEM_TYPE).toInt();

        switch (direction)
        {
            case EnumType::SquareItem_LeftTop:
                x = 0.0;
                y = 0.0;
                break;

            case EnumType::SquareItem_LeftBottom:
                x = 0.0;
                y = height - SquareItem::SQUAREITEM_WIDTH;
                break;

            case EnumType::SquareItem_RightBottom:
                x = width - SquareItem::SQUAREITEM_WIDTH;
                y = height - SquareItem::SQUAREITEM_WIDTH;
                break;

            case EnumType::SquareItem_RightTop:
                x = width - SquareItem::SQUAREITEM_WIDTH;
                y = 0.0;
                break;

            default:
                break;
        }

        squareItem->setPos(x,y);

    }
}

// 辅助函数（设置端口圆点DotItem的是否显示）
void BlockItemClass::setDotItemVisible(bool is_Visible)
{
    foreach (DotItem *dotItem, m_DotItem_List)
    {
        dotItem->setVisible(is_Visible);
    }
}

// 辅助函数（设置缩放小正方形SquareItem的是否显示）
void BlockItemClass::setSquareItemVisible(bool is_Visible)
{
    foreach (SquareItem *squareItem, m_SquareItem_List)
    {
        squareItem->setVisible(is_Visible);
    }
}

// 公有函数（设置圆点DotItem的是否可以被选中）
void BlockItemClass::setDotItemIsSelectable(bool flag)
{

    if(flag)
    {
        foreach (DotItem *dotItem, m_DotItem_List)
        {
            dotItem->setFlags(QGraphicsItem::ItemIsSelectable);
        }
    }
    else
    {
        foreach (DotItem *dotItem, m_DotItem_List)
        {
            dotItem->setFlags(dotItem->flags()&~QGraphicsItem::ItemIsSelectable);
        }
    }
}

// 公有函数（设置小正方形SquareItem是否可以被选中）
void BlockItemClass::setSquareItemIsSelectable(bool flag)
{
    if(flag)
    {
        foreach (SquareItem *squareItem, m_SquareItem_List)
        {
            squareItem->setFlags(QGraphicsItem::ItemIsSelectable);
        }
    }
    else
    {
        foreach (SquareItem *squareItem, m_SquareItem_List)
        {
            squareItem->setFlags(squareItem->flags()&~QGraphicsItem::ItemIsSelectable);
        }
    }
}

// 辅助函数（碰撞检测）
bool BlockItemClass::collidingItems(void)
{
    // 获取所有碰撞检测到的QGraphicsItem（包括自己的子Item）
    QList<QGraphicsItem *> QGraphicsItemList = m_BlockItem->collidingItems();

    foreach(QGraphicsItem *tempItem, QGraphicsItemList)
    {
        // 如果子Item的父BlockItem不是此BlockItem，且为空(不加为空判断会问题)
        if(tempItem->data(ITEM_CLASS).toInt() == EnumType::ItemClass_FLowBlockItem)
        {
            return true;
        }
    }

    return false;
}

int BlockItemClass::getBlockID() const
{
    return m_BlockID;
}

// 公有函数
DotItem *BlockItemClass::getDotItemByDirection(int DotItem_Direction)
{
    DotItem *dotItem;

    for (int i = 0; i < m_DotItem_List.size(); ++i)
    {
        dotItem = m_DotItem_List.at(i);
        if(dotItem->data(ITEM_TYPE).toInt() == DotItem_Direction)
            return dotItem;
    }
    return Q_NULLPTR;
}



QJsonObject BlockItemClass::toJsonObj(void)
{
    QJsonObject jsonObj;
    QJsonArray jsonObj_Pos;
    QJsonObject jsonSubObj;
    QJsonArray jsonTextFontColor;

    QFont textItemFont;
    QColor itemItemFontColor;

    int blockItem_ID,blockItem_TypeID;
    qreal blockItem_Width,blockItem_Height;
    QString blockItem_TextItem_Text,blockItem_TextItem_Font;
    int blockItem_TextItem_FontSize;
    int blockItem_TextItem_Alignment;

    itemItemFontColor = m_TextItem->defaultTextColor();

    blockItem_ID = m_BlockID;
    blockItem_TypeID = this->m_BlockType;
    blockItem_Width = m_BlockItem->boundingRect().width();
    blockItem_Height = m_BlockItem->boundingRect().height();
    blockItem_TextItem_Text = m_TextItem->toPlainText();

    textItemFont = m_TextItem->font();
    blockItem_TextItem_Font = textItemFont.family();
    blockItem_TextItem_FontSize = textItemFont.pixelSize();

    auto document = m_TextItem->document();
    auto option = document->defaultTextOption();

    blockItem_TextItem_Alignment = option.alignment();

    jsonObj_Pos.append(m_BlockItem->scenePos().rx());
    jsonObj_Pos.append(m_BlockItem->scenePos().ry());

    jsonObj.insert("BlockItem_ID",QJsonValue(blockItem_ID));
    jsonObj.insert("BlockItem_TypeID",QJsonValue(blockItem_TypeID));
    jsonObj.insert("BlockItem_Pos",QJsonValue(jsonObj_Pos));
    jsonObj.insert("BlockItem_Width",QJsonValue(blockItem_Width));
    jsonObj.insert("BlockItem_Height",QJsonValue(blockItem_Height));

    jsonSubObj.insert("Text",QJsonValue(blockItem_TextItem_Text));
    jsonSubObj.insert("Font",QJsonValue(textItemFont.toString()));
    jsonSubObj.insert("FontSize",QJsonValue(blockItem_TextItem_FontSize));

    jsonTextFontColor.append(itemItemFontColor.red());
    jsonTextFontColor.append(itemItemFontColor.green());
    jsonTextFontColor.append(itemItemFontColor.blue());
    jsonTextFontColor.append(itemItemFontColor.alpha());
    jsonSubObj.insert("FontColor",QJsonValue(jsonTextFontColor));

    jsonSubObj.insert("Alignment",QJsonValue(blockItem_TextItem_Alignment));

    jsonObj.insert("BlockItem_TextItem",QJsonValue(jsonSubObj));

    return jsonObj;

}

QList<SquareItem *> BlockItemClass::getSquareItem_List() const
{
    return m_SquareItem_List;
}

QList<DotItem *> BlockItemClass::getDotItem_List() const
{
    return m_DotItem_List;
}

TextItem *BlockItemClass::getTextItem() const
{
    return m_TextItem;
}

FlowBlockItem *BlockItemClass::getBlockItem() const
{
    return m_BlockItem;
}






